//#include "stdafx.h"
#include "../../../BGAudioEngine/stdafx.h"
#include "AudioHostForKS.h"
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"setupapi.lib")
#ifdef DEBUG
#include <fstream>
#endif

CAudioHostForKS::CAudioHostForKS(void)
	: m_pEnumerator (NULL)
	, m_pCEnumerator (NULL)
	, m_pFilter (NULL)
	, m_pPin (NULL)
	, m_pCFilter (NULL)
	, m_pCPin (NULL)
	, m_fIsVista (FALSE)
	, m_nLDevs(0)
	, m_nCDevs(0)
	, m_fIsRun(FALSE)
	, m_iCurLDev(0)
	, m_iCurCDev(0)
	, m_pVSTArray(NULL)
	, m_hThread(NULL)
	, m_nBufferSize(441*4)
	, m_iInChannels(2)
	, m_nVolume(100)
	, m_nVST(0)
	, MAX_BUFFER_SIZE(128000)
	, MIN_BUFFER_SIZE(128)
	, m_eDrvType(KERNEL_STREAM)
	, m_pDSO(NULL)
	, m_fVstChanged(FALSE)
{
	LISTPOS pos=NULL;
	DWORD dwVersion = GetVersion();
	// Get the Windows version.
	DWORD dwWindowsMajorVersion =  (DWORD)(LOBYTE(LOWORD(dwVersion)));
	if(dwWindowsMajorVersion>5)
		m_fIsVista = TRUE;
	for(int i=0;i<16;++i){
		memset(&m_pszLDevNames[i][0],0,128);
		memset(&m_pszCDevNames[i][0],0,128);
	}
	for (int i = 0; i < (sizeof(m_hControlEvents)/sizeof(HANDLE)); ++i)
		m_hControlEvents[i] = ::CreateEvent(NULL, FALSE, FALSE, NULL);
	CreateEnumRen();
	m_pFilter=NULL;
	m_pEnumerator->m_listFilters.GetHead((CKsFilter**)&m_pFilter);
	int n=(int)m_pEnumerator->m_listFilters.GetCount();
	m_nLDevs=n;
	if(n>0)
		pos=m_pEnumerator->m_listFilters.GetHeadPosition();
	for (int i = 0; i < n; ++i){
		m_pFilter=NULL;
		m_pEnumerator->m_listFilters.GetNext(pos,(CKsFilter**)&m_pFilter);
		char *s=m_pFilter->GetFriendlyName();
		strcpy(m_pszLDevNames[i],s);
	}
	m_pEnumerator->DestroyLists();
	delete m_pEnumerator;
	m_pEnumerator=NULL;
	CreateEnumCap();
	m_pCFilter=NULL;
	m_pCEnumerator->m_listFilters.GetHead((CKsFilter**)&m_pCFilter);
	n=(int)m_pCEnumerator->m_listFilters.GetCount();
	m_nCDevs=n;
	if(n>0)
		pos=m_pCEnumerator->m_listFilters.GetHeadPosition();
	for (int i = 0; i < n; ++i){
		m_pCFilter=NULL;
		m_pCEnumerator->m_listFilters.GetNext(pos,(CKsFilter**)&m_pCFilter);
		char *s=m_pCFilter->GetFriendlyName();
		strcpy(m_pszCDevNames[i],s);
	}
	m_pCEnumerator->DestroyLists();
	delete m_pCEnumerator;
	m_pCEnumerator=NULL;
	InitializeCriticalSection (&m_cs) ;
	g_lDebugLevel = TRACE_ALWAYS;
	memset(&m_wfx,0,sizeof(WAVEFORMATEX));
	m_wfx.nChannels = 2;
    m_wfx.nSamplesPerSec = 44100;
    m_wfx.nBlockAlign = 4;
    m_wfx.nAvgBytesPerSec = m_wfx.nSamplesPerSec * m_wfx.nBlockAlign;
    m_wfx.wBitsPerSample = 16;
}

CAudioHostForKS::~CAudioHostForKS(void)
{
	if(m_fIsRun)
		Stop();
	for (int i = 0; i < 2; ++i){
		if(m_hControlEvents[i]){
			try{
				CloseHandle(m_hControlEvents[i]);
				m_hControlEvents[i]=NULL;
			}
			catch(...)
			{
				continue;
			}
		}
	}
	if(m_pVSTArray)
	{
		free(m_pVSTArray);
		m_pVSTArray=NULL;
		m_nVST=0;
	}
	DeleteCriticalSection (&m_cs) ;
}

HRESULT CAudioHostForKS::CreateEnumRen()
{
	HRESULT hr;
	m_pEnumerator = new CKsEnumFilters(&hr);
	if(m_pEnumerator==NULL||!SUCCEEDED(hr)){
		::MessageBox(NULL,"Can not create KS Enumerator,Program would exit!","ERROR",MB_OK);
	}
	GUID  aguidEnumCats[] = { STATIC_KSCATEGORY_AUDIO, /*STATIC_KSCATEGORY_MIXER*/STATIC_KSCATEGORY_RENDER };
	hr = 
		m_pEnumerator->EnumFilters
		(
			eAudRen,            // create audio render filters ...
			aguidEnumCats,      // ... of these categories
			2,                  // There are 2 categories
			TRUE,               // While you're at it, enumerate the pins
			FALSE,              // ... but don't bother with nodes
			TRUE                // Instantiate the filters
		);
	return hr;
}

HRESULT CAudioHostForKS::CreateEnumCap()
{
	HRESULT hr;
	m_pCEnumerator = new CKsEnumFilters(&hr);
	if(m_pCEnumerator==NULL||!SUCCEEDED(hr)){
		::MessageBox(NULL,"Can not create KS Capture Enumerator,Program would exit!","ERROR",MB_OK);
	}
	GUID  aguidEnumCatsCap[] = { STATIC_KSCATEGORY_AUDIO, STATIC_KSCATEGORY_CAPTURE };
	hr = 
		m_pCEnumerator->EnumFilters
		(
			eAudCap,            // create audio render filters ...
			aguidEnumCatsCap,      // ... of these categories
			2,                  // There are 2 categories
			TRUE,               // While you're at it, enumerate the pins
			FALSE,              // ... but don't bother with nodes
			TRUE                // Instantiate the filters
		);
	return hr;
}

int CAudioHostForKS::GetListenDeviceCount(void)
{
	return m_nLDevs;
}

int CAudioHostForKS::GetCaptureDeviceCount(void)
{
	return m_nCDevs;
}

char* CAudioHostForKS::GetListenDeviceName(int i)
{
	if(i<0||i>=m_nLDevs||m_nLDevs==0)
		return NULL;
	return m_pszLDevNames[i];
}

char* CAudioHostForKS::GetCaptureDeviceName(int i)
{
	if(i<0||i>=m_nCDevs||m_nCDevs==0)
		return NULL;
	return m_pszCDevNames[i];
}

int CAudioHostForKS::GetCurrentListenDevice(void)
{
	return m_iCurLDev;
}

BOOL CAudioHostForKS::SetCurrentListenDevice(int i)
{
	if(m_fIsRun)
		return FALSE;
	switch(m_eDrvType)
	{
		case DIRECT_SOUND:
			if(m_pDSO->SetDevice(i))
			{
				m_iCurLDev=i;
				return TRUE;
			}
			break;
		case KERNEL_STREAM:
			m_iCurLDev=i;
			LISTPOS pos=NULL;
			char* s=m_pszLDevNames[i];
			CreateEnumRen();
			m_pFilter=NULL;
			m_pEnumerator->m_listFilters.GetHead((CKsFilter**)&m_pFilter);
			pos=m_pEnumerator->m_listFilters.GetHeadPosition();
			do{
				m_pFilter=NULL;
				m_pEnumerator->m_listFilters.GetNext(pos,(CKsFilter**)&m_pFilter);
				if(stricmp(m_pFilter->GetFriendlyName(),s)==0)
					return TRUE;
			}while(m_pFilter);
			m_pFilter=NULL;
			m_pEnumerator->DestroyLists();
			delete m_pEnumerator;
			m_pEnumerator=NULL;
			break;
	}
	return FALSE;
}

BOOL CAudioHostForKS::SetCurrentListenDeviceByName(char* szDeviceName)
{
	for(int i=0;i<m_nLDevs;++i){
		if(stricmp(szDeviceName,m_pszLDevNames[i])==0){
			return SetCurrentListenDevice(i);
		}
	}
	return FALSE;
}

int CAudioHostForKS::GetCurrentCaptureDevice(void)
{
	return m_iCurCDev;
}

BOOL CAudioHostForKS::SetCurrentCaptureDevice(int i)
{
	if(m_fIsRun)
		return FALSE;
	m_iCurCDev=i;
	LISTPOS pos=NULL;
	char* s=m_pszCDevNames[i];
	CreateEnumCap();
	m_pCFilter=NULL;
	m_pCEnumerator->m_listFilters.GetHead((CKsFilter**)&m_pCFilter);
	pos=m_pCEnumerator->m_listFilters.GetHeadPosition();
	do{
		m_pCFilter=NULL;
		m_pCEnumerator->m_listFilters.GetNext(pos,(CKsFilter**)&m_pCFilter);
		if(stricmp(m_pCFilter->GetFriendlyName(),s)==0)
			return TRUE;
	}while(m_pCFilter);
	m_pCFilter=NULL;
	m_pCEnumerator->DestroyLists();
	delete m_pCEnumerator;
	m_pCEnumerator=NULL;
	return FALSE;
}

BOOL CAudioHostForKS::SetCurrentCaptureDeviceByName(char* szDeviceName)
{
	for(int i=0;i<m_nCDevs;++i){
		if(stricmp(szDeviceName,m_pszCDevNames[i])==0){
			return SetCurrentCaptureDevice(i);
		}
	}
	return FALSE;
}

//------------------------------------------------------------------------------

DWORD WINAPI WorkThreadProc(LPVOID pParam)
{
#ifdef DEBUG
	std::ofstream f("Debug_Delays.txt");
	int nDelayRec=0;
	DWORD nDelayTimer=::GetTickCount();
#endif

	CAudioHostForKS* pAH=(CAudioHostForKS*)pParam;
	
	if(pAH->pMixer)
	{
		pAH->SetSampleRate(pAH->m_wfx.nSamplesPerSec);
		CAudioHost* pao=(CAudioHost*)pAH;
		pao->SetBufferSize((long)(pAH->m_nBufferSize)/pAH->m_wfx.nBlockAlign);
	}

	const int nBuffers=3;
	const int nEvents=nBuffers*2+2;
	HRESULT hr=S_OK;
	
	HANDLE hEvents[nEvents]={0};//hEvents: 0-nBuffers=Listen Events; nBuffers-2*nBuffers=Capture Events ; last 2=Control Events
	for(int i=nEvents-(sizeof(pAH->m_hControlEvents)/sizeof(HANDLE))-1;
		i<nEvents;
		++i){
			hEvents[i]=pAH->m_hControlEvents[i-2*nBuffers];
	}
	
	DWORD dwControlCode=0;
	BOOL fDone=FALSE;
	DWORD dwWait;
	int nBufferSize=pAH->m_nBufferSize;
	PBYTE pBuffer=new BYTE[nBufferSize*nBuffers*2];
	CWavVstHost** pVSTs=NULL;
	int nVSTs=0;

	EnterCriticalSection (&pAH->m_cs);
	if(pAH->m_fVstChanged)
	{
		pVSTs=pAH->m_pVSTArray;
		nVSTs=pAH->m_nVST;
		if(pVSTs){
			for(int i=0;i<nVSTs;++i)
			{
				pVSTs[i]->SetBuffer(pAH->m_wfx.nSamplesPerSec,nBufferSize/(pAH->m_wfx.nBlockAlign));
			}
		}
		pAH->m_fVstChanged=FALSE;
	}
	LeaveCriticalSection (&pAH->m_cs);

	DATA_PACKET Packets[nBuffers*2];
    for (int i = 0; i < nBuffers*2; ++i)
    {
        Zero(Packets[i]);
		Packets[i].Signal.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		hEvents[i] = Packets[i].Signal.hEvent;
        Packets[i].Header.Data = pBuffer + i * nBufferSize;
		Packets[i].Header.PresentationTime.Numerator = 1;
		Packets[i].Header.PresentationTime.Denominator = 1;
		Packets[i].Header.Size = sizeof(Packets[i].Header);
		if(i<nBuffers){
			Packets[i].Header.DataUsed = nBufferSize;//cbPartialBuffer;  //Listen Events
			Packets[i].Header.FrameExtent = nBufferSize;
		}
		else{
			Packets[i].Header.DataUsed = 0;//cbPartialBuffer;  //Capture Events, if we were capturing, we would init this to 0
			if(pAH->m_iInChannels==1){
				Packets[i].Header.FrameExtent = nBufferSize>>1;
			}
			else{
				Packets[i].Header.FrameExtent = nBufferSize;
			}
		}
    }
	int NBS=pAH->m_wfx.wBitsPerSample/8;//N Bytes Per Sample, no bigger than 4;
	if(NBS>4||NBS<1)
		return -1;
	int nSamples=nBufferSize/(NBS<<1);
	KSSTATE State = KSSTATE_STOP;
	DWORD BitMask=0;
	switch(NBS)
	{
		case 1:
			BitMask=0x000000ff;
			break;
		case 2:
			BitMask=0x0000ffff;
			break;
		case 3:
			BitMask=0x00ffffff;
			break;
		case 4:
			BitMask=0xffffffff;
			break;
	}

	DWORD NgtMask=0;//Negative
	switch(NBS)
	{
		case 1:
			NgtMask=0xffffff00;
			break;
		case 2:
			NgtMask=0xffff0000;
			break;
		case 3:
			NgtMask=0xff000000;
			break;
		case 4:
			NgtMask=0x00000000;
			break;
	}

	while(!fDone){
		dwWait=WaitForMultipleObjects( (nEvents-nBuffers), &hEvents[nBuffers], FALSE, INFINITE);
		if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT))
			break;
		dwWait -= WAIT_OBJECT_0;
		if(dwWait<nBuffers){
			if(State!=KSSTATE_STOP){

#ifdef DEBUG
				if(nDelayRec>=100){
					{
						nDelayTimer-=::GetTickCount();
						f<<nDelayTimer<<std::endl;
					}
					nDelayRec=0;
				}				
#endif

				int current=dwWait+nBuffers;
				int next=((dwWait+1)%nBuffers)+nBuffers;
				Packets[next].Header.DataUsed=0;
				hr = pAH->m_pCPin->ReadData(&Packets[next].Header, &Packets[next].Signal);
				
				BYTE* pB=(BYTE*)Packets[current].Header.Data;
				
				if(pAH->m_iInChannels==1){
					BYTE tb=0;
					DWORD tbp1=0,tbp2=0;
					for(int i=nSamples-1;i>=0;i--){//copy from offset tbp2 to tbp1
						tbp1=i*2*NBS;
						tbp2=i*NBS;
						for(int j=0;j<NBS;++j){
							tb=pB[tbp2];
							pB[tbp1]=tb;
							pB[tbp1+NBS]=tb;
							++tbp1;
							++tbp2;
						}
					}
				}
#ifdef DEBUG
				f.write((char*)Packets[current].Header.Data,nBufferSize);
#endif
				long tS=0;
				EnterCriticalSection (&pAH->m_cs);
				for(int i=0;i<nBufferSize;i+=NBS){
					tS=(long)(((DWORD)(*((long*)(&pB[i]))))&BitMask);
					if((long(((DWORD)tS)<<((4-NBS)<<3)))<0)
					{
						tS|=NgtMask;
					}
					tS*=((long)pAH->m_nVolume);
					tS/=100;
					for(int j=0;j<NBS;++j)
					{
						pB[i+j]=((BYTE*)&tS)[j];
					}
					//pB[i]=(short)(((long)pB[i])*((long)pAH->m_nVolume)/100);
				}
				if(pAH->m_fVstChanged)
				{
					pVSTs=pAH->m_pVSTArray;
					nVSTs=pAH->m_nVST;
					if(pVSTs){
						for(int i=0;i<nVSTs;++i)
						{
							pVSTs[i]->SetBuffer(pAH->m_wfx.nSamplesPerSec,nBufferSize/(pAH->m_wfx.nBlockAlign));
						}
					}
					pAH->m_fVstChanged=FALSE;
				}
				if(pVSTs){
					for(int i=0;i<nVSTs;++i)
					{
						pVSTs[i]->Process((PVOID)Packets[current].Header.Data);
					}
				}
				LeaveCriticalSection (&pAH->m_cs);
				////////////////////////////////////////////////////////////////
				switch(pAH->m_wfx.nBlockAlign)
				{
					case 2:
						pAH->HandleSamples8Bit((char*)Packets[current].Header.Data,pAH->m_nBufferSize);
						break;
					case 4:
						pAH->HandleSamples16Bit((char*)Packets[current].Header.Data,pAH->m_nBufferSize);
						break;
					case 6:
						break;
					case 8:
						pAH->HandleSamples32Bit((char*)Packets[current].Header.Data,pAH->m_nBufferSize);
						break;
				}
				////////////////////////////////////////////////////////////////
				if(pAH->m_eDrvType==CAudioHostForKS::KERNEL_STREAM)
				{
					dwWait=WaitForMultipleObjects( nBuffers, hEvents, FALSE, INFINITE);
					dwWait -= WAIT_OBJECT_0;
					memcpy(Packets[dwWait].Header.Data,Packets[current].Header.Data,nBufferSize);

#ifdef DEBUG
					if(nDelayRec>=100){
						nDelayTimer=::GetTickCount();
					}
					else{
						++nDelayRec;
					}
#endif

					hr = pAH->m_pPin->WriteData(&Packets[dwWait].Header, &Packets[dwWait].Signal);
				}
				else if(pAH->m_eDrvType==CAudioHostForKS::DIRECT_SOUND)
				{
					dwWait=WaitForMultipleObjects( 2, pAH->m_pDSO->m_hMainBufferEvent, FALSE, INFINITE);
					dwWait -= WAIT_OBJECT_0;
					pAH->m_pDSO->FillMainBuffer((PBYTE)(Packets[current].Header.Data),dwWait);
				}
			}
			else{
				fDone=TRUE;
			}
			{

			}
		}
		else{
			dwControlCode=dwWait-nBuffers;
			switch(dwControlCode){
				case eRun:
					State = KSSTATE_RUN;
					for(int i=0;i<nBuffers;++i){
						SetEvent(Packets[i].Signal.hEvent);
					}
					if(pAH->m_eDrvType==CAudioHostForKS::KERNEL_STREAM)
					{
						pAH->m_pPin->SetState(State);
					}
					pAH->m_pCPin->SetState(State);
					pAH->m_pCPin->ReadData(&Packets[nBuffers].Header, &Packets[nBuffers].Signal);
					//pAH->m_pPin->WriteData(&Packets[0].Header, &Packets[0].Signal);
					break;
				case eStop:
					State = KSSTATE_STOP;
					if(pAH->m_eDrvType==CAudioHostForKS::KERNEL_STREAM)
					{
						pAH->m_pPin->SetState(State);
					}
					pAH->m_pCPin->SetState(State);
					fDone=TRUE;
					break;
				default:
					break;
			}
		}			
	}
	if(pBuffer){
		delete []pBuffer;
		pBuffer=NULL;
	}
	for (int i = 0; i < nBuffers*2; ++i)
    {
		CloseHandle(Packets[i].Signal.hEvent);
		Packets[i].Signal.hEvent=NULL;
	}
	return 0;
}
// ----------------------------------------------------------------------
HANDLE CAudioHostForKS::CreateWorkThreads(LPTHREAD_START_ROUTINE lpThreadProc)
{
    DWORD   dwID;
    HANDLE  hThread;
	CAudioHostForKS* pParameter = this;
    hThread = CreateThread(NULL, 0,lpThreadProc, pParameter, 0, &dwID);
	::SetThreadPriority(hThread,THREAD_PRIORITY_TIME_CRITICAL);
    return hThread;
}

BOOL CAudioHostForKS::CreatePins(void)
{
	try
    {
		// instantiate the pin as 16bit, 48KHz, stereo
        // use WAVEFORMATEXTENSIBLE to describe wave format
        WAVEFORMATEXTENSIBLE wfx;
		memcpy(&wfx.Format,&m_wfx,sizeof(WAVEFORMATEX));
        wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
        /*wfx.Format.nChannels = 2;
        wfx.Format.nSamplesPerSec = 48000;
        wfx.Format.nBlockAlign = 4;
        wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
        wfx.Format.wBitsPerSample = 16;*/
        wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
        wfx.Samples.wValidBitsPerSample = wfx.Format.wBitsPerSample;
        wfx.dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT;
        wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

		
		if(m_eDrvType==KERNEL_STREAM)
		{
			m_pPin = m_pFilter->CreateRenderPin(&wfx.Format, FALSE);
		}

		wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
        // set unused members to zero
        wfx.Format.cbSize = 0;
        wfx.Samples.wValidBitsPerSample = 0;
        wfx.dwChannelMask = 0;
        wfx.SubFormat = GUID_NULL;
		
		m_pCPin = m_pCFilter->CreateCapturePin(&wfx.Format,FALSE);
		
		m_iInChannels=2;

		DWORD dwT=(DWORD)IOCTL_KS_READ_STREAM;
		dwT=(DWORD)IOCTL_KS_WRITE_STREAM;
		dwT=(DWORD)IOCTL_KS_PROPERTY;
		dwT=(DWORD)IOCTL_KS_RESET_STATE;

		if(m_eDrvType==KERNEL_STREAM)
		{
			if (!m_pPin)
			{
				// driver can't handle WAVEFORMATEXTENSIBLE, so fall back to
				// WAVEFORMATEX format descriptor and try again
				m_pPin = m_pFilter->CreateRenderPin(&wfx.Format, FALSE);
			}
		}
		if(!m_pCPin)
		{
			// driver can't handle WAVEFORMATEXTENSIBLE, so fall back to
            // WAVEFORMATEX format descriptor and try again
			wfx.Format.nChannels = 1;
			wfx.Format.nBlockAlign = 2;
			wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
			//wfx.Format.nSamplesPerSec = 24000;
			
			m_pCPin = m_pCFilter->CreateCapturePin(&wfx.Format,FALSE);
			m_iInChannels=1;
		}

        ThrowOnNull(m_pPin, "No pins available for rendering");
		ThrowOnNull(m_pCPin, "No pins available for capturing");
	}
	catch(LPSTR strErr)
	{
		char exp[512]={0};
		sprintf(exp,"An Exception Occured In CreatePins() Method:\r\n%s",strErr);
		//AfxMessageBox(exp);
		return FALSE;
	}
	return TRUE;
}

void CAudioHostForKS::DeletePins(void)
{
	if(m_pPin){
		m_pPin->SetState(KSSTATE_STOP);
		m_pPin->ClosePin();
		m_pPin=NULL;
	}
	if(m_pCPin){
		m_pCPin->SetState(KSSTATE_STOP);
		m_pCPin->ClosePin();
		m_pCPin=NULL;
	}
}

BOOL CAudioHostForKS::Start(void)
{
	if(m_fIsRun)
		return FALSE;
	if(m_eDrvType==KERNEL_STREAM)
	{
		if(m_pEnumerator==NULL)
			SetCurrentListenDevice(m_iCurLDev);
	}
	if(m_pCEnumerator==NULL)
		SetCurrentCaptureDevice(m_iCurCDev);
	if(!CreatePins())
		return FALSE;
	for(int i=0;i<(sizeof(m_hControlEvents)/sizeof(HANDLE));++i){
		ResetEvent(m_hControlEvents[i]);
	}
	m_hThread=CreateWorkThreads(WorkThreadProc);
	m_fIsRun=TRUE;
	if(m_eDrvType==DIRECT_SOUND)
	{
		m_pDSO->Start();
	}
	SetEvent(m_hControlEvents[eRun]);
	return TRUE;
}

void CAudioHostForKS::Stop(void)
{
	if(!m_fIsRun)
		return;
	SetEvent(m_hControlEvents[eStop]);
	if(WAIT_TIMEOUT==WaitForSingleObject(m_hThread,4000))
	{
		if(m_eDrvType==KERNEL_STREAM)
		{
			m_pPin->SetState(KSSTATE_STOP);
		}
		else if(m_eDrvType==DIRECT_SOUND)
		{
			m_pDSO->Stop();
		}
		
		m_pCPin->SetState(KSSTATE_STOP);
		TerminateThread(m_hThread,0);
		Sleep(1000);
	}
	m_hThread=NULL;
	DeletePins();
	if(m_eDrvType==KERNEL_STREAM)
	{
		m_pEnumerator->DestroyLists();
		delete m_pEnumerator;
		m_pEnumerator=NULL;
	}
	else if(m_eDrvType==DIRECT_SOUND)
	{
	}
	m_pCEnumerator->DestroyLists();
	delete m_pCEnumerator;
	m_pCEnumerator=NULL;
	m_fIsRun=FALSE;
}

BOOL CAudioHostForKS::SetVstEffect(CWavVstHost** pVSTArray,int nCount)
{
	if(nCount<0)
	{
		return FALSE;
	}
	EnterCriticalSection (&m_cs);
	if(m_pVSTArray)
	{
		free(m_pVSTArray);
		m_pVSTArray=NULL;
		m_nVST=0;
	}
	if(nCount>0&&pVSTArray!=NULL)
	{
		m_pVSTArray=(CWavVstHost**)malloc(sizeof(CWavVstHost*)*nCount);
		m_nVST=nCount;
		for(int i=0;i<nCount;++i)
		{
			m_pVSTArray[i]=pVSTArray[i];
		}
	}
	m_fVstChanged=TRUE;
	LeaveCriticalSection (&m_cs);
	return TRUE;
}

BOOL CAudioHostForKS::SetBufferSize(int size)
{
	if(m_fIsRun)
		return FALSE;
	if(size>MAX_BUFFER_SIZE||size<MIN_BUFFER_SIZE)
		return FALSE;
	m_nBufferSize=size;
	if(m_eDrvType==DIRECT_SOUND)
	{
		m_pDSO->SetBufferSize(size);
	}
	return TRUE;
}

int CAudioHostForKS::SetVolume(int Vol)
{
	if(Vol>100)
		Vol=100;
	if(Vol<0)
		Vol=0;
	EnterCriticalSection (&m_cs);
	m_nVolume=Vol;
	LeaveCriticalSection (&m_cs);
	return Vol;
}

int CAudioHostForKS::GetVolume(void)
{
	return m_nVolume;
}

BOOL CAudioHostForKS::SetFormat(WAVEFORMATEX* pwfx)
{
	if(m_fIsRun)
	{
		return FALSE;
	}
	if(pwfx==NULL)
	{
		return FALSE;
	}
	BOOL rt=TRUE;
	memcpy(&m_wfx,pwfx,sizeof(WAVEFORMATEX));
	switch(m_eDrvType)
	{
		case DIRECT_SOUND:
			{
				if(m_pCEnumerator==NULL)
					SetCurrentCaptureDevice(m_iCurCDev);
				if(!CreatePins())
					rt=FALSE;
				DeletePins();
				m_pCEnumerator->DestroyLists();
				delete m_pCEnumerator;
				m_pCEnumerator=NULL;
				WAVEFORMATEXTENSIBLE twfx={0};
				memcpy(&twfx.Format,&m_wfx,sizeof(WAVEFORMATEX));
				if(!m_pDSO->SetFormat(&twfx))
				{
					rt=FALSE;
				}
			}
			break;
		case KERNEL_STREAM:
			memcpy(&m_wfx,pwfx,sizeof(WAVEFORMATEX));
			if(m_pEnumerator==NULL)
				SetCurrentListenDevice(m_iCurLDev);
			if(m_pCEnumerator==NULL)
				SetCurrentCaptureDevice(m_iCurCDev);
			if(!CreatePins())
				rt=FALSE;
			DeletePins();
			m_pEnumerator->DestroyLists();
			delete m_pEnumerator;
			m_pEnumerator=NULL;
			m_pCEnumerator->DestroyLists();
			delete m_pCEnumerator;
			m_pCEnumerator=NULL;
			break;
	}
	return rt;
}

void CAudioHostForKS::GetFormat(WAVEFORMATEX* pwfx)
{
	if(pwfx)
	{
		memcpy(pwfx,&m_wfx,sizeof(WAVEFORMATEX));
	}
}

BOOL CAudioHostForKS::UseDirectSoundOutput(BOOL fUseDirectSoundOutput)
{
	if(fUseDirectSoundOutput)
	{
		if(m_pEnumerator)
		{
			m_pEnumerator->DestroyLists();
			delete m_pEnumerator;
			m_pEnumerator=NULL;
		}
		m_pDSO=new CDsoundOutput;
		if(!m_pDSO->m_fInited)
		{
			return FALSE;
		}
		memcpy(m_pszLDevNames,m_pDSO->m_pszLDevNames,128*16);
		m_iCurLDev=m_pDSO->m_iCurLDev;
		m_nLDevs=m_pDSO->m_nLDevs;
		m_eDrvType=DIRECT_SOUND;
		SetBufferSize(m_wfx.nAvgBytesPerSec*40/1000);
	}
	else
	{
		if(m_pDSO)
		{
			delete m_pDSO;
			m_pDSO=NULL;
		}
		m_eDrvType=KERNEL_STREAM;
		////////////////
		{
			memset(m_pszLDevNames,0,16*128);
			LISTPOS pos=NULL;
			if(m_pEnumerator==NULL)
				CreateEnumRen();
			m_pFilter=NULL;
			m_pEnumerator->m_listFilters.GetHead((CKsFilter**)&m_pFilter);
			int n=(int)m_pEnumerator->m_listFilters.GetCount();
			m_nLDevs=n;
			if(n>0)
				pos=m_pEnumerator->m_listFilters.GetHeadPosition();
			for (int i = 0; i < n; ++i){
				m_pFilter=NULL;
				m_pEnumerator->m_listFilters.GetNext(pos,(CKsFilter**)&m_pFilter);
				char *s=m_pFilter->GetFriendlyName();
				strcpy(m_pszLDevNames[i],s);
			}
			m_pEnumerator->DestroyLists();
			delete m_pEnumerator;
			m_pEnumerator=NULL;
		}
		////////////////
	}
	return TRUE;
}